#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter_ipv4.h>
#include <net/inet_hashtables.h>
#include <net/tcp.h>
#include <linux/inet.h>
#include <linux/inetdevice.h>

#include <linux/init.h>
#include <linux/version.h> //LINUX_VERSION_CODE

#include <net/sock.h>   //struct sock *
#include <linux/netlink.h> //netlink_kernel_create()
#include <linux/sched.h>

/*#include "netlink_k.h"*/

static struct sock  *nlfd;
static int          pid;
extern char g_local_interface[40];  //"eth0"
extern char g_mirror_interface[40]; //"eth1"
#include "tcp_hack.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LHY");
MODULE_DESCRIPTION("TCP HACK");
#define NF_PRI_TCP_HACK -500

const char local_ip[16];

static unsigned int hook_ipv4_pre_routing(unsigned int hooknum, struct sk_buff *skb,
		const struct net_device *in, const struct net_device *out,
		int (*okfn)(struct sk_buff *))
{
		return process_pre_routing(skb,in,out);//���ô���
}

static unsigned int hook_ipv6_pre_routing(unsigned int hooknum, struct sk_buff *skb,
                                          const struct net_device *in, const struct net_device *out,
                                          int (*okfn)(struct sk_buff *))
{
    return process_pre_routing_v6(skb,in,out);
}


static struct nf_hook_ops nfho[] = {
	{
		.hook = hook_ipv4_pre_routing,
		.hooknum = NF_INET_PRE_ROUTING,
		.pf = PF_INET,
		.priority = NF_PRI_TCP_HACK,
	
	}
,
    {
        .hook = hook_ipv6_pre_routing,
        .hooknum = NF_INET_PRE_ROUTING,
        .pf = PF_INET6,
        .priority = NF_PRI_TCP_HACK,

    }
};


int all_rcv(struct sk_buff *skb, struct net_device *dev,struct packet_type *pt, struct net_device *orig_dev)
{

	if(skb->pkt_type == PACKET_OTHERHOST)
	{
	//	skb->pkt_type = PACKET_HOST;
		skb->pkt_type = 7;
	}

	kfree_skb(skb);
	return NET_RX_SUCCESS;
}

static struct packet_type all_packet_type = {
	.type = __constant_htons(ETH_P_ALL),
	.func = all_rcv,
};

char * kfgets(char *s, int n, struct file * fp,loff_t *pos)
{
	char c;
	register char *cs;
	cs=s;

	while(--n>0 && 1 == vfs_read(fp,&c, 1, pos))
		if ((*cs++=  c) =='\n')
			break;
	*cs ='\0';

	return ( cs == s) ?NULL :s ;
}

int ReadConfig(char* name , int name_len, char * plocal, char * pmirror)
{
	printk("ReadConfig: begin!\n");
	if (name_len == 0 || name == NULL)
	{
		return -1;
	}
	if(plocal == NULL || pmirror == NULL)
	{
		return -1;
	}
	mm_segment_t fs;
	struct file *fp = filp_open(name,O_RDONLY,0);
	if (IS_ERR(fp))
	{
		//PDEBUG("read file error/n");
		return -1;
	}
	fs =get_fs();
	set_fs(KERNEL_DS);
	loff_t pos = 0;
	char line[100] = {0};
	memset(line, '\0', 100);
	while((kfgets(line, 100, fp, &pos)) != NULL)
	{
		if(line[0] = 'D')
		{
			if(line[strlen("Down Interface")] == '=')
			{
				strcpy(plocal, &line[strlen("Down Interface=")]);
				if(plocal[strlen(plocal)-1] == 10)
				{
					plocal[strlen(plocal)- 1] = 0;
				}
			}
		}
		if(line[0] = 'U')
		{
			if(line[strlen("Up Interface")] == '=')
			{
				strcpy(pmirror, &line[strlen("Up Interface=")]);
				if(pmirror[strlen(pmirror)-1] == 10)
				{
					pmirror[strlen(pmirror) - 1] = 0;
				}
			}
		}
		memset(line, '\0', 100);
	}
	filp_close(fp,NULL);
	set_fs(fs);
	return 0;
}

int __init hack_init(void)
{
	static char pcfg[] = "/opt/reyzar/can/etc/trafficserver/NCA.conf";
    memset(g_local_interface, '\0', 40);
    memset(g_mirror_interface, '\0', 40);
    int ret = ReadConfig(pcfg, strlen(pcfg), g_local_interface, g_mirror_interface);
	if(ret < 0)
	{
		goto failure;
	}
    printk("interface:%s, %s\n", g_local_interface, g_mirror_interface);

	struct net_device *mirror_dev = NULL, *local_dev = NULL;
	__be32 ifa_address;
	int error;
	error = nf_register_hooks(nfho, ARRAY_SIZE(nfho));
	if (error)
		goto failure;
	mirror_dev = dev_get_by_name(&init_net,g_mirror_interface);
	if(mirror_dev == NULL)
		goto failure;
	all_packet_type.dev = mirror_dev;
	dev_add_pack(&all_packet_type);
    
    printk("<1>module hack_tcp_transform init success!\n");
	return error;
failure:
	nf_unregister_hooks(nfho, ARRAY_SIZE(nfho));
	printk("<1>module hack_tcp_transform init failure!\n");
	return error;
}

void __exit hack_exit(void)
{
	nf_unregister_hooks(nfho, ARRAY_SIZE(nfho));
    dev_remove_pack(&all_packet_type);
	dev_put(all_packet_type.dev);
  printk("module hack_tcp_transform exit success\n");
}

module_init(hack_init);
module_exit(hack_exit);
